use core::f32;
use std::{cell::RefCell, cmp::Ordering, collections::HashMap, hash::Hash, rc::Rc};

use serde::{ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple, SerializeTupleStruct, SerializeTupleVariant}, Serialize};

#[derive(Hash, Eq, PartialEq, Debug, Clone)]
pub enum PreprocessType {
    Int(i128),
    F32(F32Type),
    F64(F64Type),
    String(String),
}

impl PartialOrd for PreprocessType {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for PreprocessType {
    fn cmp(&self, other: &Self) -> Ordering {
        match (self, other) {
            (PreprocessType::String(_), PreprocessType::String(_)) => {
                if let PreprocessType::String(s1) = self {
                    if let PreprocessType::String(s2) = other {
                        return s1.cmp(s2);
                    }
                }
                Ordering::Equal
            }
            (PreprocessType::F64(_), PreprocessType::F64(_)) => {
                if let PreprocessType::F64(f1) = self {
                    if let PreprocessType::F64(f2) = other {
                        return f1.union.cmp(&f2.union);
                    }
                }
                Ordering::Equal
            }
            (PreprocessType::F32(_), PreprocessType::F32(_)) => {
                if let PreprocessType::F32(f1) = self {
                    if let PreprocessType::F32(f2) = other {
                        return f1.union.cmp(&f2.union);
                    }
                }
                Ordering::Equal
            }
            (PreprocessType::Int(_), PreprocessType::Int(_)) => {
                if let PreprocessType::Int(i1) = self {
                    if let PreprocessType::Int(i2) = other {
                        return i1.cmp(i2);
                    }
                }
                Ordering::Equal
            }
            (PreprocessType::String(_), _) => Ordering::Greater,
            (_, PreprocessType::String(_)) => Ordering::Less,
            (PreprocessType::F64(_), _) => Ordering::Greater,
            (_, PreprocessType::F64(_)) => Ordering::Less,
            (PreprocessType::F32(_), _) => Ordering::Greater,
            (_, PreprocessType::F32(_)) => Ordering::Less,
        }
    }
}

impl PreprocessType {
    pub fn serialize<T>(&self, serializer:T)->Result<T::Ok, T::Error>
        where T:serde::Serializer{
        match self {
            PreprocessType::Int(i) => i.serialize(serializer),
            PreprocessType::F32(F32Type { value, .. })=>value.serialize(serializer),
            PreprocessType::F64(F64Type { value, .. })=>value.serialize(serializer),
            PreprocessType::String(str) => str.serialize(serializer),
        }
    }
}

#[derive(Debug, Clone)]
pub struct F32Type{
    pub value:f32,
    union:u32
}

impl F32Type {
    pub fn new(value:f32)->Self {
        F32Type {
            value,
            union:u32::from_le_bytes(value.to_le_bytes())
        }
    }
}

impl Hash for F32Type {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.union.hash(state);
    }
}

impl PartialEq for F32Type {
    fn eq(&self, other: &Self) -> bool {
        self.union == other.union
    }
}

impl Eq for F32Type {}

#[derive(Debug, Clone)]
pub struct F64Type{
    pub value:f64,
    union:u64
}

impl F64Type {
    pub fn new(value:f64)->Self {
        F64Type {
            value,
            union:u64::from_le_bytes(value.to_le_bytes())
        }
    }
}

impl Hash for F64Type {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.union.hash(state);
    }
}

impl PartialEq for F64Type {
    fn eq(&self, other: &Self) -> bool {
        self.union == other.union
    }
}

impl Eq for F64Type {}

#[derive(Default, Debug, Clone)]
pub struct PreprocessorData {
    pub value_counter:HashMap<PreprocessType, usize>,
}

impl PreprocessorData {
    pub fn insert_int(&mut self, value: i128) {
        if value >=0 && value < 0xf {
            return;
        }
        let counter = self.value_counter.entry(PreprocessType::Int(value)).or_insert(0);
        *counter += 1;
    }

    pub fn insert_f32(&mut self, value: f32) {
        let counter = self.value_counter.entry(PreprocessType::F32(F32Type::new(value))).or_insert(0);
        *counter += 1;
    }

    pub fn insert_f64(&mut self, value: f64) {
        let counter = self.value_counter.entry(PreprocessType::F64(F64Type::new(value))).or_insert(0);
        *counter += 1;
    }

    pub fn insert_string(&mut self, value: String) {
        let counter = self.value_counter.entry(PreprocessType::String(value)).or_insert(0);
        *counter += 1;
    }

    pub fn gengrate_refdata(&self)->PreprocessorRefData {
        type DataInfo = (PreprocessType, usize);
        let mut  datas: Vec<DataInfo> = self.value_counter.iter()
            .filter(|(_, &value)| value > 1)
            .map(|(key, &value)| (key.clone(), value))
            .collect();
        datas.sort_by(|(k1, count1), (k2, count2)| {
            if count1 != count2 {
                count2.cmp(count1)
            }
            else {
                k2.cmp(k1)
            }
        });
        let data_arr:Vec<PreprocessType> = datas.iter().map(|(v,_)|{
            v.clone()
        }).collect();
        PreprocessorRefData::new(data_arr)
    }
}

pub struct PreprocessorRefData{
    hash_data:HashMap<PreprocessType, usize>,
    arr_data:Vec<PreprocessType>,
}

impl PreprocessorRefData{
    pub fn new(arr_data:Vec<PreprocessType>)->Self{
        let hash_data:HashMap<_, _> = arr_data.iter().enumerate()
            .map(|(index, value)|{
                (value.clone(), index)
            }).collect();
        PreprocessorRefData {
            arr_data,
            hash_data
        }
    }

    pub fn get_int_refindex(&self, v:i128)->Option<&usize>{
        return self.hash_data.get(&PreprocessType::Int(v));
    }

    pub fn get_f32_refindex(&self, v:f32)->Option<&usize> {
        return self.hash_data.get(&PreprocessType::F32(F32Type::new(v)));
    }
    
    pub fn get_f64_refindex(&self, v:f64)->Option<&usize> {
        return self.hash_data.get(&PreprocessType::F64(F64Type::new(v)));
    }

    pub fn get_string_refindex(&self, str:String)->Option<&usize> {
        return self.hash_data.get(&PreprocessType::String(str));
    }

    pub fn get_ref_array(&self)-> &Vec<PreprocessType> {
        &self.arr_data
    }

    pub fn has_ref_data(&self)->bool {
        !self.arr_data.is_empty()
    }

    pub fn get_ref_array_mut(&mut self)->&mut Vec<PreprocessType> {
        &mut self.arr_data
    }
}

pub struct Preprocessor {
    data:Rc<RefCell<PreprocessorData>>
}

impl Preprocessor {
    pub fn new()->Preprocessor{
        Preprocessor {
            data: Rc::new(RefCell::new(PreprocessorData::default()))
        }
    }
}

impl From<Rc<RefCell<PreprocessorData>>> for Preprocessor {
    fn from(value: Rc<RefCell<PreprocessorData>>) -> Self {
        Preprocessor {
            data: value
        }
    }
}

impl SerializeSeq for Preprocessor {
    type Ok = Rc<RefCell<PreprocessorData>>;

    type Error = crate::error::Error;

    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize {
        value.serialize(Preprocessor::from(self.data.clone()))?;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        Ok(self.data)
    }
}

impl SerializeTuple for Preprocessor {
    type Ok = Rc<RefCell<PreprocessorData>>;

    type Error = crate::error::Error;

    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize {
        value.serialize(Preprocessor::from(self.data.clone()))?;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        Ok(self.data)
    }
}

impl SerializeTupleStruct for Preprocessor {
    type Ok = Rc<RefCell<PreprocessorData>>;

    type Error = crate::error::Error;

    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize {
        value.serialize(Preprocessor::from(self.data.clone()))?;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        Ok(self.data)
    }
}

impl SerializeTupleVariant for Preprocessor {
    type Ok = Rc<RefCell<PreprocessorData>>;

    type Error = crate::error::Error;

    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize {
        value.serialize(Preprocessor::from(self.data.clone()))?;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        Ok(self.data)
    }
}

impl SerializeMap for Preprocessor {
    type Ok = Rc<RefCell<PreprocessorData>>;

    type Error = crate::error::Error;

    fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize {
        key.serialize(Preprocessor::from(self.data.clone()))?;
        Ok(())
    }

    fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize {
        value.serialize(Preprocessor::from(self.data.clone()))?;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        Ok(self.data)
    }
}

impl SerializeStruct for Preprocessor {
    type Ok = Rc<RefCell<PreprocessorData>>;

    type Error = crate::error::Error;

    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize {
        {self.data.borrow_mut().insert_string(key.to_string());}
        value.serialize(Preprocessor::from(self.data.clone()))?;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        Ok(self.data)
    }
}

impl SerializeStructVariant for Preprocessor {
    type Ok = Rc<RefCell<PreprocessorData>>;

    type Error = crate::error::Error;

    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + Serialize {
        {self.data.borrow_mut().insert_string(key.to_string());}
        value.serialize(Preprocessor::from(self.data.clone()))?;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        Ok(self.data)
    }
}

impl serde::Serializer for Preprocessor {
    type Ok = Rc<RefCell<PreprocessorData>>;

    type Error = crate::error::Error;

    type SerializeSeq = Self;

    type SerializeTuple = Self;

    type SerializeTupleStruct = Self;

    type SerializeTupleVariant = Self;

    type SerializeMap = Self;

    type SerializeStruct = Self;

    type SerializeStructVariant = Self;

    fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
        Ok(self.data)
    }

    fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_int(v as i128);
        Ok(self.data)
    }

    fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_int(v as i128);
        Ok(self.data)
    }

    fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_int(v as i128);
        Ok(self.data)
    }

    fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_int(v as i128);
        Ok(self.data)
    }

    fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_int(v);
        Ok(self.data)
    }
    fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_int(v as i128);
        Ok(self.data)
    }

    fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_int(v as i128);
        Ok(self.data)
    }

    fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_int(v as i128);
        Ok(self.data)
    }

    fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_int(v as i128);
        Ok(self.data)
    }

    fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_int(v as i128);
        Ok(self.data)
    }

    fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_f32(v);
        Ok(self.data)
    }

    fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_f64(v);
        Ok(self.data)
    }

    fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_string(v.to_string());
        Ok(self.data)
    }

    fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
        self.data.borrow_mut().insert_string(v.to_string());
        Ok(self.data)
    }

    fn serialize_bytes(self, values: &[u8]) -> Result<Self::Ok, Self::Error> {
        {
            let mut data = self.data.borrow_mut();
            for v in values {
                data.insert_int((*v) as i128);
            }
        }
        Ok(self.data)
    }

    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
        Ok(self.data)
    }

    fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
    where
        T: ?Sized + serde::Serialize {
        value.serialize(Preprocessor::from(self.data.clone()))
    }

    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
        Ok(self.data)
    }

    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
        Ok(self.data)
    }

    fn serialize_unit_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        variant: &'static str,
    ) -> Result<Self::Ok, Self::Error> {
        // name.serialize(Preprocessor::from(self.data.clone()))?;
        variant.serialize(Preprocessor::from(self.data.clone()))
    }

    fn serialize_newtype_struct<T>(
        self,
        _name: &'static str,
        value: &T,
    ) -> Result<Self::Ok, Self::Error>
    where
        T: ?Sized + serde::Serialize {
        // name.serialize(Preprocessor::from(self.data.clone()))?;
        value.serialize(Preprocessor::from(self.data.clone()))
    }

    fn serialize_newtype_variant<T>(
        self,
        _name: &'static str,
        _variant_index: u32,
        variant: &'static str,
        value: &T,
    ) -> Result<Self::Ok, Self::Error>
    where
        T: ?Sized + serde::Serialize {
        // name.serialize(Preprocessor::from(self.data.clone()))?;
        variant.serialize(Preprocessor::from(self.data.clone()))?;
        value.serialize(Preprocessor::from(self.data.clone()))
    }

    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
        Ok(self)
    }

    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
        Ok(self)
    }

    fn serialize_tuple_struct(
        self,
        _name: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
        // name.serialize(Preprocessor::from(self.data.clone()))?;
        Ok(self)
    }

    fn serialize_tuple_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        variant: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
        // name.serialize(Preprocessor::from(self.data.clone()))?;
        variant.serialize(Preprocessor::from(self.data.clone()))?;
        Ok(self)
    }

    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
        Ok(self)
    }

    fn serialize_struct(
        self,
        _name: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeStruct, Self::Error> {
        // name.serialize(Preprocessor::from(self.data.clone()))?;
        Ok(self)
    }

    fn serialize_struct_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        variant: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeStructVariant, Self::Error> {
        // name.serialize(Preprocessor::from(self.data.clone()))?;
        variant.serialize(Preprocessor::from(self.data.clone()))?;
        Ok(self)
    }
}
